package com.oh.core.common.utils;

import com.oh.core.common.cache.ChannelStore;
import com.oh.core.common.constant.CommandEnum;
import com.oh.core.common.constant.ConfigConst;
import com.oh.core.entity.HeadInfo;
import com.oh.core.entity.MessageEntity;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

/**
 * 消息工具
 */
public class MessageUtils {

    private static final Logger log = LoggerFactory.getLogger(MessageUtils.class);
    /**
     * int 转 byte数组 高字节在前（高字节序）
     * @param n 数据
     * @return byte[]
     */
    public static byte[] toHH(int n) {
        byte[] b = new byte[4];
        b[3] = (byte) (n & 0xff);
        b[2] = (byte) (n >> 8 & 0xff);
        b[1] = (byte) (n >> 16 & 0xff);
        b[0] = (byte) (n >> 24 & 0xff);
        return b;
    }

    /**
     * int 转 byte[]   低字节在前（低字节序）
     * @param n int
     * @return bytes
     */
    public static byte[] toLH(int n) {
        byte[] b = new byte[4];
        b[0] = (byte) (n & 0xff);
        b[1] = (byte) (n >> 8 & 0xff);
        b[2] = (byte) (n >> 16 & 0xff);
        b[3] = (byte) (n >> 24 & 0xff);
        return b;
    }

    /**
     * byte[] 转 int 低字节在前（低字节序）
     * @param b bytes
     * @return int
     */
    public static int toLInt(byte[] b){
        int res = 0;
        for(int i=0;i<b.length;i++){
            res += (b[i] & 0xff) << (i*8);
        }
        return res;
    }

    /**
     * byte[] 转 int 高字节在前（高字节序）
     * @param b 字节
     * @return int
     */
    public static int toHInt(byte[] b){
        int res = 0;
        for(int i=0;i<b.length;i++){
            res += (b[i] & 0xff) << ((3-i)*8);
        }
        return res;
    }

    /**
     * 打包消息，消息头11个长度
     * @param command 1-1 指令
     * @param magic 2-4 魔数
     * 3-4 报文长度
     * @param content 4 数据
     * @return 报文
     */
    public static byte [] splicingMsg(byte command, int magic, byte [] content) throws Exception {
        // 消息头
        byte [] data = new byte[ConfigConst.HEAD_LEN + content.length];
        data[0] = command;
        byte [] magicTmp = toHH(magic);// 魔数 4个长度
        System.arraycopy(magicTmp, 0, data, 1, magicTmp.length);
        int length = content.length;
        byte [] lengthTmp = toHH(length); // 长度 4个长度
        System.arraycopy(lengthTmp, 0, data, 5, lengthTmp.length);
        // 消息体
        System.arraycopy(content, 0, data, 9, length);
        return data;
    }

    /**
     * 打包消息，消息头11个长度
     * @param command 1-1 指令
     * @param content 4 数据
     * @return 报文
     */
    public static byte [] splicingMsg(byte command, byte [] content) throws Exception {
        return splicingMsg(command, ConfigConst.MAGIC_NUMBER, content);
    }

    /**
     * 解析消息
     * @param content 报文
     * @return 返回消息体
     */
    public static byte [] getBody(byte [] content) throws Exception {
        if(content.length < ConfigConst.HEAD_LEN){
            throw new Exception("字节数不足，至少" + ConfigConst.HEAD_LEN + "个字节长度！");
        }
        byte [] body = new byte[content.length - ConfigConst.HEAD_LEN];
        System.arraycopy(content, ConfigConst.HEAD_LEN, body, 0, content.length - ConfigConst.HEAD_LEN);
        return body;
    }

    /**
     * 获取消息头
     * @param data 报文
     * @return 返回消息头
     */
    public static HeadInfo getHead(byte [] data) throws Exception {
        if(data.length < ConfigConst.HEAD_LEN){
            throw new Exception("字节数不足，至少" + ConfigConst.HEAD_LEN + "个字节长度！");
        }
        HeadInfo headInfo = new HeadInfo();
        headInfo.setCommand(data[0]); // 指令
        byte [] magicBytes = new byte[4]; // 魔数
        System.arraycopy(data, 1, magicBytes, 0, 4);
        headInfo.setMagic(MessageUtils.toHInt(magicBytes));
        // 长度
        byte [] lengthByte = new byte[4];
        System.arraycopy(data, 5, lengthByte, 0, 4);
        headInfo.setLength(MessageUtils.toHInt(lengthByte));
        return headInfo;
    }


    /**
     * 对所有channel发生消息
     * @param content 消息
     */
    public static void sendMsgToAll(byte [] content){
        try {
            ChannelStore.getClients().writeAndFlush(MessageUtils.splicingMsg(CommandEnum.MESSAGE_REQUEST.getCommand(), content));
        } catch (Exception e) {
            log.error("消息发送异常！{}", e.getLocalizedMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送消息
     * @param clientIds 客户端ID列表
     * @param msg 消息
     */
    public static void sendMsg(List<String> clientIds, MessageEntity msg){
        if(!ObjectUtils.isEmpty(clientIds) && clientIds.size() > 0){
            clientIds.forEach(key -> {
                if(ChannelStore.containsKey(key)){
                    Channel channel = ChannelStore.getChannel(key);
                    if(channel.isWritable()){
                        channel.writeAndFlush(msg.toMsgBytes());
                    }else{
                        log.error("客户端【{}】不能发送消息！", key);
                    }
                }else{
                    log.error("未找到客户端【{}】,发送失败！", key);
                }
            });
        }
    }

    /**
     * 发送消息
     * @param clientId 客户端ID
     * @param msg 消息
     */
    public static void sendMsg(String clientId, MessageEntity msg){
        if(clientId != null && !clientId.equals("")){
            List<String> clientIds = Collections.singletonList(clientId);
            sendMsg(clientIds, msg);
        }
    }

    /**
     * 发送消息
     * @param channel 通道
     * @param msg 消息实体
     */
    public static void channelMsg(Channel channel, MessageEntity msg){
        channel.writeAndFlush(msg.toMsgBytes());
    }
}
